// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FIX42OrderPlugin.FIX.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.Forge.Plugins
{
    #region Using Directives

    using QuickFix;

    using QuickFix42;

    #endregion

    /// <summary>
    /// The fix 42 order plugin.
    /// </summary>
    public partial class FIX42OrderPlugin
    {
        /// <summary>
        /// The my application.
        /// </summary>
        internal class FIX42Application : FIXApplication
        {
            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="FIX42Application"/> class.
            /// </summary>
            /// <param name="layer">
            /// The layer.
            /// </param>
            public FIX42Application(FIX42OrderPlugin layer)
            {
                this.OrderPlugin = layer;
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets or sets OrderPlugin.
            /// </summary>
            private FIX42OrderPlugin OrderPlugin { get; set; }

            #endregion

            #region Public Methods

            /// <summary>
            /// The on message.
            /// </summary>
            /// <param name="message">
            /// The message.
            /// </param>
            /// <param name="session">
            /// The session.
            /// </param>
            public override void onMessage(ExecutionReport message, SessionID session)
            {
                // Get the order id (our order id)
                var id = new ClOrdID();
                message.get(id);

                // If no order is there for this external id, stop
                if (!this.OrderPlugin.ordersStore.HasOrder(id))
                {
                    return;
                }

                // This is the related order 
                var order = this.OrderPlugin.ordersStore.GetOrder(id);

                // Handler to send messages back
                var handler = this.OrderPlugin.handlersStore.GetHandler(order.ID);

                // Fetch fields
                var fixStatus = new OrdStatus();
                message.get(fixStatus);

                if (fixStatus.getObject().Equals(OrdStatus.NEW))
                {
                    this.OrderPlugin.RaiseEventAckOrder(order.ID, order.Way, order.Quantity, 0, order.Price, handler);
                }
                else if (fixStatus.getObject().Equals(OrdStatus.REJECTED))
                {
                    // Reason
                    var fixRejectReason = new OrdRejReason();
                    message.get(fixRejectReason);

                    // Raise event
                    var reason = fixRejectReason.ToString();
                    this.OrderPlugin.RaiseEventRejOrder(order.ID, order.Way, reason, handler);
                }
                else if (fixStatus.getObject().Equals(OrdStatus.CANCELED))
                {
                    // Remaining qty on market
                    var fixRemainingQty = new LeavesQty();
                    message.get(fixRemainingQty);

                    // Raise event(s)
                    var remQuantity = (int)fixRemainingQty.getObject();
                    var cancelledQuantity = order.Quantity - remQuantity;
                    this.OrderPlugin.RaiseEventAckCancel(order.ID, order.Way, cancelledQuantity, handler);
                }
                else if (fixStatus.getObject().Equals(OrdStatus.FILLED) || fixStatus.getObject().Equals(OrdStatus.PARTIALLY_FILLED))
                {
                    // Execution
                    var fixExecutionId = new ExecID();
                    message.get(fixExecutionId);
                    var fixExecutionPrice = new LastPx();
                    message.get(fixExecutionPrice);
                    var fixExecutionQuantity = new LastShares();
                    message.get(fixExecutionQuantity);
                    var fixRemainingQty = new LeavesQty();
                    message.get(fixRemainingQty);

                    // Raise event
                    var execQuantity = (int)fixExecutionQuantity.getObject();
                    var execPrice = (double)fixExecutionPrice.getObject();
                    var remQty = (int)fixRemainingQty.getObject();
                    this.OrderPlugin.RaiseEventOrderExecution(order.ID, order.Way, execPrice, execQuantity, remQty, handler);
                }
                else if (fixStatus.getObject().Equals(OrdStatus.FILLED))
                {
                    // Raise event
                    this.OrderPlugin.RaiseEventOutReport(order.ID, order.Way, handler);
                }
                else
                {
                    Devel.ShouldNotOccur(
                        this, "public override void onMessage(ExecutionReport message, SessionID session) : Some Status was not handled. Review code");
                }
            }

            /// <summary>
            /// The on message.
            /// </summary>
            /// <param name="message">
            /// The message.
            /// </param>
            /// <param name="session">
            /// The session.
            /// </param>
            public override void onMessage(OrderCancelReject message, SessionID session)
            {
                // Get the order id (our order id)
                var id = new ClOrdID();
                message.get(id);

                // If no order is there for this external id, stop
                if (!this.OrderPlugin.ordersStore.HasOrder(id))
                {
                    return;
                }

                // This is the related order 
                var order = this.OrderPlugin.ordersStore.GetOrder(id);

                // Handler to send messages back
                var handler = this.OrderPlugin.handlersStore.GetHandler(order.ID);

                // Raise event
                var reason = "unknown";
                this.OrderPlugin.RaiseEventRejCancel(order.ID, order.Way, reason, handler);
            }

            /// <summary>
            /// The on message.
            /// </summary>
            /// <param name="message">
            /// The message.
            /// </param>
            /// <param name="session">
            /// The session.
            /// </param>
            public override void onMessage(OrderCancelReplaceRequest message, SessionID session)
            {
                // Get the order id (our order id)
                var id = new ClOrdID();
                message.get(id);

                // If no order is there for this external id, stop
                if (!this.OrderPlugin.ordersStore.HasOrder(id))
                {
                    return;
                }

                // This is the related order 
                var order = this.OrderPlugin.ordersStore.GetOrder(id);

                // Handler to send messages back
                var handler = this.OrderPlugin.handlersStore.GetHandler(order.ID);

                // Raise event
                var reason = "unknown";
                this.OrderPlugin.RaiseEventRejModify(order.ID, order.Way, reason, handler);
            }

            /// <summary>
            /// The on message.
            /// </summary>
            /// <param name="message">
            /// The message.
            /// </param>
            /// <param name="session">
            /// The session.
            /// </param>
            public override void onMessage(OrderCancelRequest message, SessionID session)
            {
                Devel.ShouldNotOccur(this, "Implement public override void onMessage(OrderCancelRequest message, SessionID session)");
            }

            /// <summary>
            /// The on message.
            /// </summary>
            /// <param name="message">
            /// The message.
            /// </param>
            /// <param name="session">
            /// The session.
            /// </param>
            public override void onMessage(OrderStatusRequest message, SessionID session)
            {
                Devel.ShouldNotOccur(this, "Implement onMessage(OrderStatusRequest message, SessionID session)");
            }

            #endregion
        }
    }
}